<?php

namespace app\logic\fp;

use app\common\enum\fp\PaymentType;
use app\common\library\Upload;
use app\common\model\fp\Post;
use app\common\model\fp\PostAudit;
use app\common\model\fp\PostLike;
use app\common\model\fp\PostMedia;
use app\common\model\subscribe\Subscribe;
use app\common\model\User;
use app\common\model\UserFollow;
use app\logic\BaseLogic;
use app\logic\es\fp\EsPost;
use app\logic\subscribe\SubscribeLogic;
use app\logic\user\UserLogic;
use Elastic\Elasticsearch\Exception\ClientResponseException;
use Elastic\Elasticsearch\Exception\ServerResponseException;
use Elastic\Elasticsearch\Response\Elasticsearch;
use Http\Promise\Promise;
use think\facade\Event;
use think\facade\Log;

class PostLogic extends BaseLogic
{
    protected $uploadDriver;

    public function __construct()
    {
        $upload = new Upload();
        $conf = get_upload_config();
        $this->uploadDriver = $upload->getDriver($conf['mode'], false);
    }

    /**
     * 获取可见性列表
     *
     * 该方法返回一个关联数组，包含了不同可见性状态的字符串标识和其对应的国际化翻译标识
     * 使用 ArrayShape 属性来声明返回数组的结构，以确保代码的可读性和类型安全
     *
     * @return array 返回一个关联数组，键为可见性状态的常量，值为相应的翻译标识
     */
    public static function getPaymentType(): array
    {
        // 返回包含可见性状态及其翻译标识的关联数组
        return [
            PaymentType::FREE->value => __('free'),
            PaymentType::PAID->value => __('paid'),
        ];
    }


    public function insert(array $data): array
    {
        $model = \app\common\model\fp\Post::initModel($data['user_id']);

        $model->startTrans();
        try {
            $time = time();
            $post = [
                'title' => $data['title'] ?? '',
                'type' => $data['type'] ?? 0,
                'user_id' => $data['user_id'],
                'content' => $data['content'],
                'payment_type' => $data['payment_type'],
                'price' => $data['price'] ?? 0,
                'is_vip_unlock' => $data['is_vip_unlock'] ?? 0,
                'create_time' => $time,
            ];
            $model->save($post);
            $id = $model->getLastInsID();
            $post['id'] = $id;

            $media = [];
            foreach ($data['media_url'] as $path) {
                $media[] = [
                    'id' => \app\common\library\SnowFlake::generateParticle(),
                    'post_id' => $id,
                    'media_type' => $data['media_type'],
                    'media_url' => $path,
                    'create_time' => $time,
                ];
            }

            if ($media) {
                \app\common\model\fp\PostMedia::initModel($data['user_id'])->insertAll($media);
            }

            $auditId = \app\common\library\SnowFlake::generateParticle();
            PostAudit::initModel()->insert([
                'id'=> $auditId,
                'type' => $data['type'] ?? 0,
                'media_type' => $data['media_type'],
                'post_id' => $id,
                'user_id' => $data['user_id'],
                'create_time' => $time,
            ]);
            $model->commit();

            //注册事件
            Event::trigger('postCreate', ['post_id' => $id, 'user_id' => $data['user_id'], 'audit_id'=>$auditId]);
        } catch (\Throwable $e) {
            Log::channel('my')->error($e->getMessage() . PHP_EOL . $e->getTraceAsString());
            $model->rollback();
            throw $e;
        }
        return $post;
    }

    /**
     * 关注者的动态
     * @param array $params
     * @return array
     * @throws ClientResponseException
     * @throws ServerResponseException
     */
    public function follow(array $params): array
    {
        $params['user_ids'] = UserFollow::initModel()
            ->where('follower_id', $params['auth_user_id'])
            ->column('followee_id');
        // 执行搜索
        $response = EsPost::getInstance()->findByUserIds($params);

        return $this->extracted($response, $params['size']);
    }

    /**
     * 订阅者动态
     * @param array $params
     * @return array
     * @throws ClientResponseException
     * @throws ServerResponseException
     * @throws \Throwable
     */
    public function subscribe(array $params): array
    {
        $params['user_ids'] = Subscribe::initModel()->where('user_id', $params['auth_user_id'])
            ->where('expire_time', '>', time())
            ->column('subscribe_user_id');

        $response = EsPost::getInstance()->findByUserIds($params);

        return $this->extracted($response, $params['size']);
    }

    /**
     * 视频
     * @param array $params
     * @return array
     * @throws ClientResponseException
     * @throws ServerResponseException
     */
    public function video(array $params): array
    {
        // 执行搜索
        $response = EsPost::getInstance()->video($params);

        return $this->extracted($response, $params['size']);
    }

    /**
     * 点赞过的动态
     * @param array $params
     * @return array
     * @throws ClientResponseException
     * @throws ServerResponseException
     * @throws \Throwable
     */
    public function like(array $params): array
    {
        $params['ids'] = PostLike::initModel($params['auth_user_id'])
            ->where('user_id', $params['auth_user_id'])
            ->column('post_id');
        // 执行搜索
        return $this->_findByIds($params);
    }

    /**
     * 解锁过的动态
     * @param $params
     * @return array
     * @throws ClientResponseException
     * @throws ServerResponseException
     * @throws \Throwable
     */
    public function unlock($params): array
    {
        $params['ids'] = PostUnlockedLogic::getInstance()->getUnlockedIdsByUid($params['auth_user_id']);

        // 执行搜索
        return $this->_findByIds($params);
    }


    /**
     * @param $params
     * @return array
     * @throws ClientResponseException
     * @throws ServerResponseException
     */
    public function _findByIds($params): array
    {
        $response = EsPost::getInstance()->findByIds($params);

        return $this->extracted($response, $params['size']);
    }


    public function vip($params): array
    {
        $response = EsPost::getInstance()->vip($params);

        return $this->extracted($response, $params['size']);
    }

    /**
     * 默认列表
     * @param array $params
     * @return array
     * @throws ClientResponseException
     * @throws ServerResponseException
     */
    public function all(array $params): array
    {
        // 执行搜索
        $response = EsPost::getInstance()->all($params);

        return $this->extracted($response, $params['size']);
    }

    /**
     * 处理列表结构
     * @param Elasticsearch|Promise $response
     * @param $size
     * @return array
     */
    public function extracted(Elasticsearch|Promise $response, $size): array
    {
        $result = $response->asArray();

        if (empty($result['hits'])) {
            throw new \RuntimeException(__('No results found'));
        }
        $total = $result['hits']['total']['value'] ?? 0;
        $data = $result['hits']['hits'] ?? [];

        $list = [];
        foreach ($data as $row) {
            $list[] = $row['_source'];
        }

        return ['total' => $total, 'page_size' => $size, 'list' => $list];
    }

    /**
     * 搜索动态
     * @param array $params
     * @return array
     * @throws ClientResponseException
     * @throws ServerResponseException
     */
    public function search(array $params): array
    {
        // 执行搜索
        $response = EsPost::getInstance()->query($params);

        $result = $response->asArray();
        if (empty($result['hits'])) {
            throw new \RuntimeException(__('No results found'));
        }
        $total = $result['hits']['total']['value'] ?? 0;
        $data = $result['hits']['hits'] ?? [];

        $list = [];
        foreach ($data as $row) {
            $temp = $row['_source'];
            $temp['highlight'] = $row['highlight'] ?? [];
            $list[] = $temp;
        }

        return ['total' => $total, 'page_size' => $params['size'], 'list' => $list];
    }


    /**
     * 审核帖子
     *
     * 本函数用于审核帖子，通过更新帖子的审核状态、审核人和审核时间来完成审核流程
     *
     * @param array $param 包含审核所需信息的数组，包括帖子ID、审核用户ID和审核状态
     * @return array 返回操作过后的模型
     *
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException|\Throwable
     */
    public function audit(array $param): array
    {
        // 实例化PostAudit模型，用于后续的数据库操作
        $model = PostAudit::initModel();
        $model->startTrans();
        try {
            // 根据提供的ID查询待审核的帖子记录
            $audit = $model->where('id', $param['id'])->find();

            // 如果没有找到待审核的记录，抛出运行时异常
            if (!$audit) {
                throw new \RuntimeException(__("audit record not found"));
            }

            $data = [
                'audit_user_id' => $param['audit_user_id'],
                'video_cover_url' => $param['video_cover_url'],
                'status' => $param['status'],
                'update_time' => time(),
                'audit_reason'=>$param['audit_reason'] ?? ''
            ];
            PostAudit::initModel()->where('id', $param['id'])->update($data);

            Post::initModel($audit['user_id'])->where('id', $audit['post_id'])->update(['status' => $param['status']]);
            $model->commit();
        } catch (\Throwable $e) {
            Log::channel('my')->error($e->getMessage() . PHP_EOL . $e->getTraceAsString());
            $model->rollback();
            throw $e;
        }

        // 审核流程完成，返回true
        return $model->where('id', $param['id'])->find()->toArray();
    }

    /**
     * 媒体签名
     * @param array $media 媒体信息
     * @param bool $isUnlock 当前登录的用户
     * @return array
     */
    public function mediaSignUrl(array $media, bool $isUnlock = false): array
    {
        $timeout = 24 * 60 * 60 * 3;
        if (!empty($media['media_url'])) {
            //原图模糊化
            $options = [
                'x-oss-process' => 'image/auto-orient,1/quality,q_90/blur,r_40,s_20'
            ];

            //缩略图不模糊
            $thumbOptions = [
                'x-oss-process'=>'image/auto-orient,1/resize,m_lfit,w_660,h_660/crop,g_center/quality,q_70'
            ];
            //缩略图模糊
            $thumbOptionsMh = [
                'x-oss-process'=>'image/auto-orient,1/resize,m_lfit,w_660,h_660/crop,g_center/quality,q_70/blur,r_40,s_20'
            ];
            $media['media_url_thumb'] = [];
            if ($media['media_type'] == 'image') {
                foreach ($media['media_url'] as $i => &$value) {
                    if ($isUnlock) {
                        $tempOptions = [];
                        $tempThumbOptions = $thumbOptions;
                    } else{
                        if ($i > 0) {
                            $tempOptions = $options;
                            $tempThumbOptions = $thumbOptionsMh;
                        } else {
                            //原图首图 不模糊
                            $tempOptions = [];
                            //缩略图首图 不模糊
                            $tempThumbOptions = $thumbOptions;
                        }
                    }
                    $media['media_url_thumb'][] = method_exists($this->uploadDriver, 'signUrl') ? $this->uploadDriver->signUrl($value, $timeout, $tempThumbOptions) : $value;
                    $value = method_exists($this->uploadDriver, 'signUrl') ? $this->uploadDriver->signUrl($value, $timeout, $tempOptions) : $value;
                }

            } else {
                if (!empty($media['video_cover_url'])) {
                    if ($isUnlock) {
                        $options = [];
                    }
                    $media['video_cover_url'] = method_exists($this->uploadDriver, 'signUrl') ? $this->uploadDriver->signUrl($media['video_cover_url'], $timeout, $options) : $media['video_cover_url'];
                }
                if ($isUnlock) {
                    foreach ($media['media_url'] as $i => &$value) {
                        $value = method_exists($this->uploadDriver, 'signUrl') ? $this->uploadDriver->signUrl($value, $timeout) : $value;
                    }
                } else {
                    $media['media_url'] = [];
                }
            }

        }
        return $media;
    }

    /**
     * 用户ID获取最新的动态
     * @param string $author_id 达人ID
     * @param string $user_id 当前用户ID
     * @return array
     * @throws \Throwable
     */
    public function getUserLastPost(string $author_id, string $user_id): array
    {
        $data = \app\common\model\fp\Post::initModel($author_id)->order("create_time desc")->find();

        if ($data) {
            $data = $data->toArray();
            $media = PostMedia::initModel($author_id)
                ->where('post_id', $data['id'])
                ->field('media_type,video_cover_url, media_url')
                ->select()
                ->toArray();
            $media_url = array_column($media, 'media_url');
            $media = [
                'media_type' => $media[0]['media_type'],
                'video_cover_url' => $media[0]['video_cover_url'],
                'media_url' => $media_url
            ];
            $data['is_like'] = PostLikeLogic::getInstance()->isLike($data['id'], $user_id);
            $data['is_subscribe'] = SubscribeLogic::getInstance()->isSubscribe($author_id, $user_id);
            if (!$data['is_subscribe']) {
                $data['is_unlocked'] = PostUnlockedLogic::getInstance()->isUnlockedByPost($user_id, $data['id']);
            } else {
                $data['is_unlocked'] = true;
            }
            $data['like_count'] = PostLikeLogic::getInstance()->getLikeCount($data['id'], $author_id);
            $data['comment_count'] = PostCommentLogic::getInstance()->getCommentCount($data['id']);
            $data['tips'] = UserLogic::getInstance()->tips($author_id);
            $user = User::initModel()->where('id', $data['user_id'])->field('is_creator,avatar, vip, vip_expire')->find()->toArray();
            if ($user['vip_expire'] < time()) {
                $user['vip'] = 0;
            }
            unset($user['vip_expire']);
            $data['user'] = $user;
            $data['user']['is_creator'] = (int)$user['is_creator'];
            $unlocked = $data['is_unlocked'] || $data['is_subscribe'] || $author_id == $user_id;
            $data['media']  = $this->mediaSignUrl($media, $unlocked);
        }

        return $data;
    }

    /**
     * 管理员查询单条数据
     * @param string $id
     * @param string $user_id
     * @return array
     * @throws \Throwable
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function adminGetInfo(string $id, string $user_id): array
    {
        $data = \app\common\model\fp\Post::initModel($user_id)->where('id', $id)->find()->toArray();
        $media = PostMedia::initModel($user_id)
            ->where('post_id', $data['id'])
            ->select()
            ->toArray();
        $media_url = array_column($media, 'media_url');
        $media = [
            'media_type' => $media[0]['media_type'],
            'video_cover_url' => $media[0]['video_cover_url'],
            'media_url' => $media_url
        ];
        $data['media']  = $this->mediaSignUrl($media, true);

        return $data;
    }

    /**
     * 检查是否存在
     * @param string $id
     * @param string $user_id
     * @return bool
     * @throws \Throwable
     */
    public function checkExist(string $id, string $user_id): bool
    {
        return \app\common\model\fp\Post::initModel($user_id)->where('id', $id)->find()->isExists();
    }

    /**
     * 查询单条
     * @param string $id
     * @param string $user_id
     * @return bool
     * @throws \Throwable
     */
    public function getInfo(string $id, string $user_id): bool
    {
        return \app\common\model\fp\Post::initModel($user_id)->where('id', $id)->find();
    }



}